/**
 * 
 */
package jnzb.control.queue.change;

import jnzb.control.DownloadStartedListener;
import jnzb.control.NZBProcessor;
import jnzb.control.events.InfoEventProcessor;
import jnzb.control.queue.QueueManager;
import jnzb.control.uiUpdate.UIUpdateDelegate;
import jnzb.model.nzb.NZB;

/**
 * Class to perform a queue up action across the application
 * 
 * @author AA1
 * 
 */
// TODO - have a watchdog (timertask) in here to re-enable buttons after a set
// time.
public abstract class QueueChangeProcessor implements Runnable,
		DownloadStartedListener {

	protected NZBProcessor nzbProcessor;
	protected int selectedRow;
	private boolean affectsCurrentDownload;
	protected UIUpdateDelegate uiDelegate;
	protected QueueManager queueManager;
	protected InfoEventProcessor infoProcessor;

	public QueueChangeProcessor(NZBProcessor nzbProcessor,
			UIUpdateDelegate uiDelegate, InfoEventProcessor infoProcessor,
			int selectedRow) {
		this.nzbProcessor = nzbProcessor;
		this.uiDelegate = uiDelegate;
		this.queueManager = nzbProcessor.getQueueManager();
		this.selectedRow = selectedRow;
		this.infoProcessor = infoProcessor;
		// if second element (1) then need to disable buttons while change is
		// made
		this.affectsCurrentDownload = affectsDownload(selectedRow);
	}

	@Override
	public void run() {
		infoProcessor.info("Actioning queue change");

		// Disable buttons if needed
		if (affectsCurrentDownload) {
			uiDelegate.disableQueueControlButtons();
		}

		// Make queue and display change
		NZB affectedNZB = queueManager.getNZBAt(selectedRow);
		makeQueueChange(affectedNZB);

		// tell NZB processor there's been a queue change
		notifyNZBProcessorOfQueueChange();

		// Only need to stop current download and wait for change to take effect
		// if the change affects the current download
		if (affectsCurrentDownload) {

			// Wait until the change has been affected
			boolean changeMade = false;
			while (!changeMade) {
				synchronized (this) {
					try {
						nzbProcessor.registerDownloadFinishedListener(this);
						infoProcessor.info("Actioning queue change (waiting)");
						wait();
						// Check that the change has been made
						changeMade = checkChangeMade(affectedNZB);
					} catch (InterruptedException e) {
						// Dont do anything
					}

				}
			}
			// If buttons were disabled, re-enable
			uiDelegate.enableQueueControlButtons();
		}

		infoProcessor.info("Queue change made");

	}

	/**
	 * This is the default implementation - but for remove it's slightly different
	 */
	protected void notifyNZBProcessorOfQueueChange() {
		if (affectsCurrentDownload) {
			nzbProcessor.queueChanged();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jnzb.control.QueueChangeListener#queueChanged()
	 */
	@Override
	public synchronized void downloadStarted() {
		infoProcessor.debug("Queue changed");
		notifyAll();
	}

	/**
	 * Determine if this type of change on the affected row affects the current
	 * download
	 * 
	 * @param selectedRow2
	 * @return
	 */
	public abstract boolean affectsDownload(int selectedRow2);

	/**
	 * Make the queue change for this operation
	 * 
	 * @param affectedNZB
	 */
	public abstract void makeQueueChange(NZB affectedNZB);

	/**
	 * Check that this queue change has been made. Note that this will only be
	 * called if affectsDownload() returned true
	 * 
	 * @return
	 */
	public abstract boolean checkChangeMade(NZB affectedNZB);

}
